<?php

namespace Yousheng\Ku\Commands;

use  Yousheng\Ku\Contracts\AdminRight;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\File;
use Yousheng\Ku\Commands\KuCommand;
use Yousheng\Ku\Ku;
use Symfony\Component\Console\Attribute\AsCommand;
use Yousheng\Ku\Generators\MigrationGenerator;
use Yousheng\Ku\Mergers\MergerContainer;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Yousheng\Ku\Table;

/**
 * 生成数据迁移文件.
 *
 * 运行 php artisan ku:database:create-migrations --database=database_name
 */

#[AsCommand(
    name: 'ku:database:create-migrations',
    description: '根据数据库生成迁移文件',
    hidden: false,
    aliases: ['kum', 'kumigration']
)]
class GenerateMigrationsFromDatabaseCommand extends KuCommand implements AdminRight
{
    //public $signature = 'ku:database:create-migrations {database?}';
    protected static $templateSchema = <<<EOT
    <?php
    
    /**
     * ----------------------------------------------------------------------
     * 数据库迁移助手.功能升级中，bug请直接在加qq                                                                                  |
     * ----------------------------------------------------------------------
     * Author: daqi <2922800186@qq.com>
     * ----------------------------------------------------------------------
     * Date: 数据库迁移文件生成时间 %s
     * ----------------------------------------------------------------------
     */
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    return new class extends Migration
    {
        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
    %s
        }
    
        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down()
        {
    %s
        }
    };
    
    EOT;

    protected static $schema = [];
    public function handle(Ku $ku)
    {
        // 数据库可以参数指定，如果未指定使用项目配置中指定的
        [$database, $host, $port, $username, $password] = $this->getAppDatabaseConfig();
        $database = $this->argument('database') ?? $database;
        [$rootName, $rootPassword] = $this->getAsk();
        $force = (bool)$this->option('force');

        if (!$rootName || !$rootPassword) {
            $this->error('请指定数据库管理员用户名和密码');
            return;
        }
        //  指定要生成迁移文件的数据库名
        if (!$database) {
            $this->error('请指定数据库名');
            return;
        }


        Ku::setAdminConnectioConfig([
            'driver' => 'mysql',
            'database' => $database,
            'host' => $host,
            'port' => $port,
            'username' => $rootName,
            'password' => $rootPassword,
        ]);
        // 判断数据库是否存在
        if ($this->databaseExists($database) === false) {
            $this->error("数据库 {$database} 不存在");
            exit();
        }

        $tables = $ku->initTables($database, null, true)->getTables();
 

        if ($merge = $this->option('merge')) {
            $this->info("\n共有" . count($tables) . '张表, 生成一个数据迁移文件，包括:');
        } else {
            $this->info("\n共有" . count($tables) . '张表，每张表单独生成数据迁移文件，包括:');
        }
        // 排序，主表放在前面
        $sontofather = collect($tables)->filter(function (Table $table) {  // 过滤出有外键的表
            if (!empty($table->getForeignKeys())) {
                return true;
            }
        })->mapWithKeys(function (Table $table) { // 生成一个关联数组，[子表名=>父表名]，目的是排序，主表放在从表的前面
            $foreigns = $table->getForeignKeys();
            $k=$foreigns[0]->table;
            $v=collect($foreigns)->pluck('referenced_table')->toArray(); // 一个表依赖多个表
            return [$k => $v];
        })->all();

        $sortableTables = Ku::sortedTables(array_keys($tables), $sontofather); // 拓扑排序，主表放在前面
        $sortableTables = Arr::reject($sortableTables, function ($value) {
            return $value === "migrations"; // 删除migrations表
        });

        $up = [];
        $upTemplate = <<<EOT
                // -------------------------------- %d ------------------ %s
                Schema::create('%s', function (Blueprint \$table) {
        %s
                }); 
        EOT;

        $down = [];
        $downTemplate = <<<EOT
                Schema::dropIfExists('%s');
        EOT;

        foreach ($sortableTables as $tableName) {
            static $number = 1;
            // 判断当前表对应的迁移文件是否存在
            if ($this->migrationFileExists($tableName) && !$force) {
                $this->comment("\t TABLE: '$tableName'已存在，跳过");
                continue;
            }
            // $this->info("\t TABLE: '$tableName'开始");
            try {
                $migrationGenerator = MigrationGenerator::make($tables[$tableName])->merging(
                    MergerContainer::getEngines()
                );
                if ($merge) {
                    $up[$tableName] = sprintf($upTemplate, $number++, $tableName, $tableName, $migrationGenerator->getUp());
                    $down[] = sprintf($downTemplate, $tableName);
                } else {
                    $migrationGenerator->run(force: $force);
                }
                // $this->comment("\t TABLE: '$tableName'完成\n");
            } catch (\RuntimeException $e) {
                $this->error($e->getMessage());
            }
        }
        if ($merge) {
            $schema = sprintf(self::$templateSchema, date('Y-m-d H:i:s'), implode("\n", $up), implode("\n", $down));
            $this->comment("\n生成数据迁移文件完成\n");
            File::put(
                database_path('migrations/' . date('Y_m_d_His') . '_create_' . $database . '_database.php'),
                $schema,
                $force
            );
        }


        $this->line('<info>generate-migrations</info> command executed successfully.');
    }

    // 命令参数时，方法一：使用$signature中定义，方法二使用 AsCommand注解+configure
    protected function configure()
    {
        $this
            ->addArgument('database', InputArgument::OPTIONAL, '数据库名')
            ->addOption('force', 'f', InputOption::VALUE_NONE, '强制创建')
            ->addOption('merge', 'm', InputOption::VALUE_NONE, '是否将所有表的迁移文件合并为一个文件');
    }
    /**
     * 判断当前表的数据迁移文件是否存在
     */
    protected function migrationFileExists(string $tableName): bool
    {
        $migrationPath = database_path('migrations');
        if (!File::exists($migrationPath)) {
            return false;
        }

        $files = File::files($migrationPath);
        // $pattern = "/_create_{$tableName}_table\.php$/i";
        $pattern = "Schema::create('{$tableName}', function (Blueprint \$table)";

        foreach ($files as $file) {
            $fileContent = File::get($file->getPathname());
            if (strpos($fileContent, $pattern) !== false) {
                return true;
            }
            $escapedPattern = preg_quote($pattern, '/');
            if (preg_match("/{$escapedPattern}/", $file->getFilename())) {
                return true;
            }
        }

        return false;
    }
}
